
package com.lanhao.aot.aiui.newversion;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.CountDownLatch;

import org.java_websocket.enums.ReadyState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.lanhao.aot.aiui.websocket.DraftWithOrigin;

import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;

public class AIUIUtil {
	public static final Logger LOG = LoggerFactory.getLogger(AIUIUtil.class);
	public static Map<String, JSONObject> resultMap = Maps.newConcurrentMap();
	public static Map<String, AIUIWebSocketClient> socketCacheMap = Maps.newHashMap();
	public static Map<String, Boolean> reauthconnectMap = Maps.newConcurrentMap();
	private static final String APP_ID = "144950ed";
	private static final String API_KEY = "56dc4bd99ce295e6b8a11383ce372248";
	private static final String API_SECRET = "NTA2Zjc3NWNiY2YxOTJhNzZhNDI2NTVh";
	private static final String REQUEST_URL = "wss://aiui.xf-yun.com/v2/aiui/ws";
	public static final String SCENCE = "main_box"; // 常规场景
	public static HMac mac = new HMac(HmacAlgorithm.HmacSHA256, API_SECRET.getBytes());
	public static SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
	public static URI uri = null;
	public static DraftWithOrigin draft = new DraftWithOrigin(AIUIUtil.getWebsocketUrlOrigin(REQUEST_URL));
	
	static {
		try {
			uri = new URI(REQUEST_URL);
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		format.setTimeZone(TimeZone.getTimeZone("UTC"));
	}
	
	/**
	 * AIUI握手认证的工具方案
	 * @param url
	 * @param apiKey
	 * @param apiSecret
	 * @return
	 */
	public static String getHandShakeParams() {
		try {
			String date = format.format(new Date());
			String host = uri.getHost();
			// 参与签名的字段
			StringBuilder authorizationRaw = new StringBuilder("host: ").append(host).append("\n").//
					append("date: ").append(date).append("\n").//
					append("GET ").append(uri.getPath()).append(" HTTP/1.1");
			byte[] hexDigits = mac.digest(authorizationRaw.toString());
			String signature = Base64.getEncoder().encodeToString(hexDigits);
			String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
					API_KEY, "hmac-sha256", "host date request-line", signature);
			String authBase = Base64.getEncoder().encodeToString(authorization.getBytes());
			return String.format("%s?authorization=%s&host=%s&date=%s", REQUEST_URL, URLEncoder.encode(authBase, "UTF-8"),
					URLEncoder.encode(host, "UTF-8"), URLEncoder.encode(date, "UTF-8"));
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}
	
	public static String getWebsocketUrlOrigin(String websocketUrl) {
        websocketUrl = websocketUrl.replaceAll("ws[s]?://", "");
        return "http://" + websocketUrl.substring(0, websocketUrl.indexOf("/"));
    }
	
	public static AIUIWebSocketClient getCacheWebSocketClient(String uid) {
		AIUIWebSocketClient client = socketCacheMap.get(uid);
		try {
			CountDownLatch countDownLatch = new CountDownLatch(1);
			if (client == null) {
				URI url = new URI(AIUIUtil.getHandShakeParams());
				client = new AIUIWebSocketClient(url, AIUIUtil.draft, countDownLatch, uid);
			} else {
				client.setCountDownLatch(countDownLatch);
			}
			if (!client.isOpen()) {
				LOG.info("client未开启，在此开启或重连...");
				ReadyState readyState = client.getReadyState();
				LOG.info("通道处于非开启状态，readtState={}", readyState);
				if (ReadyState.NOT_YET_CONNECTED.equals(readyState)) {
					client.connect();
				} else if (ReadyState.CLOSING.equals(readyState) || ReadyState.CLOSED.equals(readyState)) {
					client.reconnect();
				}
			}
			while (!client.getReadyState().equals(ReadyState.OPEN)) {
				Boolean reauthconnect = reauthconnectMap.get(uid);
				if (reauthconnect != null && reauthconnect) {
					socketCacheMap.remove(uid);
					reauthconnectMap.remove(uid);
					client = getCacheWebSocketClient(uid);
					break;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		socketCacheMap.put(uid, client);
		return client;
	}
	
	/**
	  *   构建AIUI通用请求
	 * @param uid
	 * @param streamId
	 * @param reqText
	 * @return
	 */
	public static String buildCommonIntentParam(String uid, String streamId, String reqText) {
		JSONObject request = new JSONObject();
		JSONObject header = new JSONObject();
		String sn = "af577fe4cb7841ce885983cc31a4f43a";
//		header.put("sn", "af577fe4cb7841ce885983cc31a4f43a");
		header.put("app_id", APP_ID);
		header.put("stmid", streamId);
		header.put("status", 3);
		header.put("scene", "main_box");
		header.put("uid", uid);
//		header.put("pers_param", "{\"uid\":\"" + uid + "\"}");

		request.put("header", header);

		JSONObject parameter = new JSONObject();
		JSONObject nlp = new JSONObject();
		JSONObject subnlp = new JSONObject();
		subnlp.put("compress", "raw");
		subnlp.put("format", "json");
		subnlp.put("encoding", "utf8");
		nlp.put("nlp", subnlp);
		nlp.put("sn", sn); // 设备SN
		nlp.put("sub_scene", "cbm_v45"); // 星火交互认知大模型引擎指定 固定取值：cbm_v45
		nlp.put("new_session", "false"); // 是否清除本次会话历史	

		parameter.put("nlp", nlp);

		request.put("parameter", parameter);

		JSONObject payload = new JSONObject();
		JSONObject text = new JSONObject();
		text.put("compress", "raw");
		text.put("format", "plain");
		text.put("text", Base64.getEncoder().encodeToString(reqText.getBytes()));
		text.put("encoding", "utf8");
		text.put("status", 3);
		payload.put("text", text);
		
		JSONObject cbm_semantic = new JSONObject();
		cbm_semantic.put("encoding", "utf8");
		cbm_semantic.put("compress", "raw");
		cbm_semantic.put("format", "json");
		cbm_semantic.put("status", 3);
		
//		String cbmText = "{\"sn\" : \" " + sn + "\", \"pers_param\": \"{\\\"uid\\\":\\\"" + uid + "\\\"}\"}";
		String cbmText = "{\"pers_param\": \"{\\\"uid\\\":\\\"" + uid + "\\\"}\"}";
		cbm_semantic.put("text", Base64.getEncoder().encodeToString(cbmText.getBytes()));
		payload.put("cbm_semantic", cbm_semantic);
		
		request.put("payload", payload);

		return request.toString();
	}
	
	public static void main(String[] args) {
		LOG.info("开始组装AIUI-ws请求地址");
		System.out.println(getHandShakeParams());
		LOG.info("结束组装AIUI-ws请求地址");
	}
}
